/**
 * JAVACC DEMO 1.0
 */
package com.apache.excp.core.impl.imp;

import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import jxl.Cell;
import jxl.CellType;
import jxl.DateCell;
import jxl.Sheet;
import jxl.Workbook;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

import com.apache.excp.ConfigConstant;
import com.apache.excp.RuturnConfig;
import com.apache.excp.RuturnPropertyParam;
import com.apache.excp.core.manager.plugins.Execlplugins;
import com.apache.tools.StrUtil;

/**
 * description:  
 * @author  创建时间：2016-7-29
 */
public class ExeclToBeanPluginsImpl implements Execlplugins {

	private File excelFile = null;

	private RuturnConfig excelConfig = null;

	private Map<String, Object> valueMap = null;

	private List<RuturnPropertyParam> fixityList = null;
	// 完整的list
	private List<Object> modelList = new ArrayList<Object>();
	// 表头验证List
	private List<String> messageList = null;
	// 是否按列读取，当出现有列标题重复时，可以按些方法来操作
	/*
	 * isUserColumn = true时，按配制文件中配制的列号读取
	 */
	private boolean isUseColumn = false;
	// 读取操作是否执行，执行完成后，会填充modelList,successModelList,errorList数据。
	private boolean isRead = false;
	// 支持带有标题的Excel文件时，保存规则数据开始的行数，及有效列数（就是配制文件中配制的excel列头在实际excel文件出的第几列数）
	private int startTitleRow = 0;

	private int intSheet = 0;

	private String strSheet = null;

	//为excel文件中，出现重复列配制
	private List<String> excelTitleList = new ArrayList<String>();

	/**
	 * TODO execl到模型的转换插件实现.  
	 */
	@SuppressWarnings("unchecked")
	public Object execute(Map<String, Object> params) {
		String key = String.valueOf(params.get("methodName"));
		if ("validateExcelFormat".equals(key)) {
			this.excelFile = (File) params.get("excelFile");
			this.excelConfig = (RuturnConfig) params.get("modelName");
			this.valueMap = (Map<String, Object>) params.get("valueMap");
			if (null == this.valueMap) {
				this.valueMap = new HashMap<String, Object>();
			}
			return validateExcelFormat();
		} else if ("getModelList".equals(key)) {
			return getModelList();
		}
		return null;
	}

	/*
	 * 验证Excel表头格式是否正确 
	 */
	public boolean validateExcelFormat() {
		boolean boolResult = true;
		List<String> titleList = this.getExcelTitle();
		/*
		 * 对excel列做处理，把出现相同的列加编号 如果出现两个　姓名 做成 姓名，姓名_1
		 */
		List<String> tempList = new ArrayList<String>();
		for (int i = 0; i < titleList.size(); i++) {
			String temp = ConfigConstant.columnValidate(tempList, titleList.get(i));
			if (StrUtil.isNull(temp))
				temp = "--";
			tempList.add(temp);
		}

		this.messageList = new ArrayList<String>();
		Map<String, RuturnPropertyParam> pmap = this.excelConfig.getPropertyMap();
		for (Iterator<String> it = pmap.keySet().iterator(); it.hasNext();) {
			String title = (String) it.next();
			if (!tempList.contains(title)) {
				boolResult = false;
				this.messageList.add("Excel中不存在 " + title + " 列！");
			}
		}
		/*
		 * 保存验证通过的，已经被处理的excel标题
		 */
		setExcelTitleList(tempList);

		return boolResult;
	}

	/**
	 * description:  返回execl内容转换后对应的模型列表
	 */
	@SuppressWarnings("rawtypes")
	public List getModelList() {
		return this.getExcelToList(0);
	}

	/**
	 * description:  返回execl内容转换后对应的完整模型列表
	 */
	@SuppressWarnings("rawtypes")
	private List getExcelToList(int intFlag) {
		if (!isRead) {
			this.isRead = true;
			getExcelToModelList();
		}
		if (intFlag == 0) {
			return this.modelList;
		} else {
			return new ArrayList();
		}
	}

	/**
	 * description:  返回execl内容转换后对应的完整模型列表
	 */
	private void getExcelToModelList() {
		if (isUseColumn) {
			getExcelToModelListByColumn();//按配置列表读取
		} else {
			getExcelToModelListByTitle();
		}
	}

	/**
	 * description:  返回execl内容转换后对应的模型列表,按配置列表读取
	 */
	private void getExcelToModelListByColumn() {
		this.setFixity();
		try {
			String fp = this.excelFile.getPath();
			Workbook book = Workbook.getWorkbook(new FileInputStream(fp));//this.excelFile);
			Sheet sheet;
			if (StringUtils.isNotBlank(this.strSheet)) {
				sheet = book.getSheet(this.strSheet);
			} else {
				sheet = book.getSheet(this.intSheet);
			}
			int rows = sheet.getRows();
			for (int i = 1; i < sheet.getRows(); i++) {
				Object obj = this.getModelClass(excelConfig.getClassName());
				boolean flag = false;// 错误标志
				String strMessage = "";// 错误消息
				// 对excel每一列的值进行取值.
				int cloums = sheet.getColumns();
				for (int j = 0; j < sheet.getColumns(); j++) {
					// 取得Excel表头
					String excelTitleName = sheet.getCell(j, 0).getContents().trim();
					// 取得Excel值
					String value = sheet.getCell(j, i).getContents().trim();
					/*
					 * 按配制列号读取Excel文件，只修改了下面的几行代码，注释上面一行代码。
					 */
					String keycolumn = String.valueOf(j + 1);
					RuturnPropertyParam propertyBean = (RuturnPropertyParam) excelConfig.getColumnMap().get(keycolumn);

					boolean columnFlag = false;// 列错误标志
					if (propertyBean != null) {
						// 判断是否非空，非空标志 ,取值为空时设置为false
						boolean nullFlag = true;
						if (propertyBean.getIsNull().equals("N")) {
							if (value.length() < 1) {
								// 非空标志
								nullFlag = false;
								flag = true;
								strMessage = strMessage + ";列：" + excelTitleName + "-为空！";
							}
						}
						// 如果取值不空
						if (nullFlag) {
							Cell strCell = sheet.getCell(j, i);
							String msg = "列：" + excelTitleName;
							writeCellValue(propertyBean, value, strCell, columnFlag, flag, strMessage, msg);
						}
						// //做出判断,是否需要 Text/Value 值转换.
						textToValue(propertyBean, value, columnFlag, obj);
					}
				}
				/*
				 * 设置错误标志，及错误消息
				 */
				errorOrMessage(flag, obj, strMessage, true);
				/*
				 * 对在配制文件中指定需要设置为固定值的属性，设置属性中的固定值，根据传入的Map中取出，无则取其默认值
				 */
				createAttr(obj);

				this.modelList.add(obj);
			}
			book.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * description:  设置错误标识和错误信息   
	 */
	private void errorOrMessage(boolean flag, Object obj, String strMessage, boolean methodType) {
		if (flag) {
			String propertyFlag = excelConfig.getFlagMap().get("name");
			String propertyMessage = excelConfig.getMessageMap().get("name");
			if (methodType) {
				// 调整支持Map
				this.setPropertyValue(obj, propertyFlag, "1");
				// 调整支持Map
				this.setPropertyValue(obj, propertyMessage, strMessage);
			} else {
				// 调整支持Map
				if (StringUtils.isNotBlank(propertyFlag)) {
					this.setPropertyValue(obj, propertyFlag, "1");
				}
				// 调整支持Map
				if (StringUtils.isNotBlank(propertyMessage)) {
					this.setPropertyValue(obj, propertyMessage, strMessage);
				}
			}
		} else {
			String propertyFlag = excelConfig.getFlagMap().get("name");
			String propertyMessage = excelConfig.getMessageMap().get("name");
			if (methodType) {
				// 调整支持Map
				this.setPropertyValue(obj, propertyFlag, "0");
				// 支持Map时，保持Map中每个属性都存在。
				this.setPropertyValue(obj, propertyMessage, "");
			} else {
				// 调整支持Map
				if (StringUtils.isNotBlank(propertyFlag)) {
					this.setPropertyValue(obj, propertyFlag, "0");
				}
				// 支持Map时，保持Map中每个属性都存在。
				if (StringUtils.isNotBlank(propertyMessage)) {
					this.setPropertyValue(obj, propertyMessage, "");
				}
			}
		}
	}

	/**
	 * description:  对在配制文件中指定需要设置为固定值的属性，设置属性中的固定值，根据传入的Map中取出，无则取其默认值 
	 */
	private void createAttr(Object obj) {
		for (Iterator<RuturnPropertyParam> it = this.fixityList.iterator(); it.hasNext();) {
			RuturnPropertyParam propertyBean = (RuturnPropertyParam) it.next();
			Object value = this.valueMap.get(propertyBean.getName());
			if (value == null || value.toString().length() < 1) {
				value = propertyBean.getDefaultValue();
			}
			// 调整支持Map
			this.setPropertyValue(obj, propertyBean.getName(), value);
		}
	}

	public boolean isUseColumn() {
		return isUseColumn;
	}

	public void setUseColumn(boolean isUseColumn) {
		this.isUseColumn = isUseColumn;
	}

	// 取得当前行有值的列数
	private int getColumnByValue(Cell[] rowCell) {
		int column = rowCell.length;
		int intResult = column;
		for (int i = 0; i < column; i++) {
			String str = rowCell[i].getContents();
			if (StringUtils.isBlank(str)) {
				intResult--;
			}
		}
		return intResult;
	}

	//获取表头列表
	private List<String> getExcelTitle() {
		this.setFixity();
		List<String> titleList = new ArrayList<String>();
		try {
			Workbook book = Workbook.getWorkbook(this.excelFile);
			Sheet sheet;
			if (StringUtils.isNotBlank(this.strSheet)) {
				sheet = book.getSheet(this.strSheet);
			} else {
				sheet = book.getSheet(this.intSheet);
			}
			// 验证列头开始的行数，并设置列头对应的有效列数
			int rows = sheet.getRows();
			for (int i = 0; i < sheet.getRows(); i++) {
				// 验证一行有值的列数
				int intcount = this.getColumnByValue(sheet.getRow(i));
				// 属性列 - 固定值列数 = 必须配制的列数
				int intNotNullColumn = this.excelConfig.getPropertyMap().size() - fixityList.size();
				if (intNotNullColumn <= intcount) {
					startTitleRow = i;
					break;
				}
			}
			int cloumns = sheet.getColumns();
			for (int j = 0; j < sheet.getColumns(); j++) {
				String title = sheet.getCell(j, startTitleRow).getContents().trim();
				if (StrUtil.isNull(title))
					title = "--";
				titleList.add(title);
			}
			book.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return titleList;
	}

	/*
	 * 对于配置文件中,指定取固定值的属性列,先取出放到List中.无则为空
	 */
	private void setFixity() {
		List<RuturnPropertyParam> fixityList = new ArrayList<RuturnPropertyParam>();
		Map<String, RuturnPropertyParam> pmap = this.excelConfig.getPropertyMap();
		for (Iterator<RuturnPropertyParam> it = pmap.values().iterator(); it.hasNext();) {
			RuturnPropertyParam propertyBean = (RuturnPropertyParam) it.next();
			if (propertyBean.getFixity().toUpperCase().trim().equals("YES")) {
				fixityList.add(propertyBean);
			}
		}
		this.fixityList = fixityList;
	}

	/**
	 * description:  返回execl内容转换后对应的模型列表,按title名称读取
	 */
	private void getExcelToModelListByTitle() {
		try {
			Workbook book = Workbook.getWorkbook(this.excelFile);
			Sheet sheet;
			if (StringUtils.isNotBlank(this.strSheet)) {
				sheet = book.getSheet(this.strSheet);
			} else {
				sheet = book.getSheet(this.intSheet);
			}
			int intContinueCount = 0;// 设置连续空行的变量，如果有连续10个空行，就停止取数
			for (int i = startTitleRow + 1; i < sheet.getRows(); i++) {
				int intcount = getColumnByValue(sheet.getRow(i));
				if (intcount < 1) {
					intContinueCount++;
					if (intContinueCount < 11) {
						continue;
					} else {
						break;
					}
				} else {
					intContinueCount = 0;
				}
				Object obj = this.getModelClass(excelConfig.getClassName());
				boolean flag = false;// 错误标志
				String strMessage = "";// 错误消息
				int colums = sheet.getColumns();
				for (int j = 0; j < sheet.getColumns(); j++) {// 对excel每一列的值进行取值.
					// 取得Excel表头
					String excelTitleName = (String) this.excelTitleList.get(j);
					// 取得Excel值
					String value = sheet.getCell(j, i).getContents().trim();
					// 取得配置属性
					RuturnPropertyParam propertyBean = (RuturnPropertyParam) excelConfig.getPropertyMap().get(
							excelTitleName);
					boolean columnFlag = false;// 列错误标志
					if (propertyBean != null) {
						// 判断是否非空，非空标志 ,取值为空时设置为false
						boolean nullFlag = true;
						if (propertyBean.getIsNull().equals("N")) {
							if (value.length() < 1) {
								// 非空标志
								nullFlag = false;
								flag = true;
								strMessage = strMessage + "Cell[" + i + "][" + j + "]:" + excelTitleName + "-为空！";
							}
						}
						// 如果取值不空
						if (nullFlag) {
							Cell strCell = sheet.getCell(j, i);
							String msg = "Cell[" + i + "][" + j + "]:" + excelTitleName;
							writeCellValue(propertyBean, value, strCell, columnFlag, flag, strMessage, msg);
						}
						// //做出判断,是否需要 Text/Value 值转换.
						textToValue(propertyBean, value, columnFlag, obj);
					}
				}
				/*
				 * 设置错误标志，及错误消息
				 */
				errorOrMessage(flag, obj, strMessage, false);
				/*
				 * 对在配制文件中指定需要设置为固定值的属性，设置属性中的固定值，根据传入的Map中取出，无则取其默认值
				 */
				createAttr(obj);

				this.modelList.add(obj);
			}
			book.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * description:  提取列值 
	 */
	private void writeCellValue(RuturnPropertyParam propertyBean, String value, Cell strCell, boolean columnFlag,
			boolean flag, String strMessage, String msg) {
		int intLength = 0;// 长度判断
		if (StringUtils.isNotBlank(propertyBean.getMaxLength())
				&& (ConfigConstant.isValidNumber(propertyBean.getMaxLength()))) {
			intLength = Integer.parseInt(propertyBean.getMaxLength());
		}
		// 如果设置了最大长度，从右边截取指定的字符长度
		if (intLength > 0 && value.length() > intLength) {
			value = value.substring(0, intLength);
		}
		// 判断数据类型 支持 String ,Integer,Date
		if (propertyBean.getDataType().indexOf("Date") > -1) {
			String[] strTemp = propertyBean.getDataType().split(" ");
			String pattern = "";
			if (strTemp.length > 1) {
				pattern = strTemp[1];
			}
			if (strCell.getType() == CellType.DATE) {
				DateCell dateCell = (DateCell) strCell;
				Date date = dateCell.getDate();
				value = ConfigConstant.getFormatDate(date, pattern);
			} else {
				value = null;
			}
			if (value == null) {
				flag = true;
				columnFlag = true;
				strMessage = strMessage + msg + "-日期格式不正确！";
			}
		}
		if (propertyBean.getDataType().equals("Integer")) {
			if (!ConfigConstant.isValidNumber(value)) {
				flag = true;
				columnFlag = true;
				strMessage = strMessage + "-不是数字！";
			}
		}
	}

	/**
	 * 做出判断,是否需要 Text/Value 值转换.
	 */
	private void textToValue(RuturnPropertyParam propertyBean, String value, boolean columnFlag, Object obj) {
		if (propertyBean.getCodeTableName().length() > 1) {
			String valueKey = propertyBean.getCodeTableName().trim() + value;
			Object obj1 = this.valueMap.get(valueKey);
			if (obj1 == null) {
				value = "";
			} else {
				value = obj1.toString();
			}
		}
		// 设置默认值 value 先是取值，再判断是否有码表对换值
		if (value == null || value.length() < 1) {
			value = propertyBean.getDefaultValue();
		}
		if (!columnFlag) {
			// 调整支持Map
			this.setPropertyValue(obj, propertyBean.getName(), value);
		}
	}

	/**
	 * description:  给属性赋值 
	 */
	@SuppressWarnings("unchecked")
	private void setPropertyValue(Object obj, String property, Object value) {
		if (obj instanceof Map) {
			((Map<String, Object>) obj).put(property, value);
		} else {
			BeanWrapper bw = new BeanWrapperImpl(obj);
			bw.setPropertyValue(property, value);
		}
	}

	/**
	 * description:  获取模型实例 
	 */
	private Object getModelClass(String className) {
		Object obj = null;
		try {
			if ("java.util.Map".equalsIgnoreCase(className)) {
				obj = new HashMap();
			} else {
				obj = Class.forName(className).newInstance();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return obj;
	}

	private void setExcelTitleList(List<String> excelTitleList) {
		this.excelTitleList = excelTitleList;
	}
}
